package com.xinsoft.jwt;

import com.xinsoft.common.Response;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.constant.Const;
import com.xinsoft.entity.dto.SysUserDTO;
import com.xinsoft.entity.dto.SysUserDetail;
import com.xinsoft.entity.po.SysRole;
import com.xinsoft.entity.po.SysUser;
import com.xinsoft.service.SysRoleService;
import com.xinsoft.service.SysUserService;
import com.xinsoft.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author hsm
 * @description JWTservice服务
 * @createDate 2023-04-24
 */
@Slf4j
@Service
public class JwtAuthService {

    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysRoleService sysRoleService;


    @Resource
    private UserDetailsService userDetailsService;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private RedisUtil redisUtil;

    public SysUserDetail login(SysUserDTO userParam, Integer terminal){

        //检查用户名是否存在
        SysUser user = sysUserService.getSysUserByUsername(userParam.getUsername());
        if(user==null){
            throw new BDException("登录失败，该用户不存在！");
        }

        String username = userParam.getUsername();
        String password = userParam.getPassword();
        log.info("请求登录用户名:{}",username);
        log.info("请求登录密码:{}",password);
        if(terminal.equals(Const.Terminal.SYSTEM)){
            try{
                //使用用户名密码进行登录验证
                UsernamePasswordAuthenticationToken upToken =
                        new UsernamePasswordAuthenticationToken( username, password );
                Authentication authentication = authenticationManager.authenticate(upToken);
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }catch(AuthenticationException e){
                throw new BDException("登录失败，密码错误！");
            }
        }
        if(!Objects.equals(user.getStatus(),1)){
            throw new BDException("登录失败，用户被禁用！");
        }
        //生成JWT
        SysUserDetail detail = (SysUserDetail)userDetailsService.loadUserByUsername(username);
        //获取角色
        List<SysRole> roles = sysRoleService.getRoleListByUserId(detail.getId());
        String jwtToken = null;
        if(detail!=null && !CollectionUtils.isEmpty(roles)){
            Map<String,Object> map = new HashMap<>();
            map.put("id",detail.getId());
            map.put("userName",detail.getUsername());
            map.put("realName",detail.getRealName());
            map.put("email", detail.getEmail());

            jwtToken = jwtTokenUtil.generateToken(user);
            redisUtil.hmset(jwtToken,map,jwtTokenUtil.getExpiration());
        }
        log.info("成功返回token:{}",jwtToken);

        detail.setToken(jwtToken);
        return detail;
    }

    public Response logout(String token){
        if (!jwtTokenUtil.isTokenExpired(token)){
            redisUtil.del(token);
            return Response.succeed();
        }
        return Response.fail("退出登录时遇到异常！");
    }

    public SysUserDTO getUserInfo(HttpServletRequest request){

        SysUserDTO bean = new SysUserDTO();
        try {
            BeanUtils.populate(bean,jwtTokenUtil.getRedisMap(request));
        } catch (IllegalAccessException | RuntimeException | InvocationTargetException e) {
            throw new BDException("用户信息获取异常！"+e.getMessage());
        }

        return bean;
    }

    public String getTokenFromRequest() {
        HttpServletRequest request = getRequest();
        if (request != null) {
            return this.getAccessToken(request);
        }
        return null;
    }

    private HttpServletRequest getRequest() {
        ServletRequestAttributes attributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
        return attributes == null ? null : attributes.getRequest();
    }

    /**
     * 获取token
     *
     * @param request HttpServletRequest
     * @return token
     */
    public  String getAccessToken(HttpServletRequest request) {
        try {
            return request.getHeader(jwtTokenUtil.getHeader());
        } catch (Exception e) {
            return null;
        }
    }
}